package cn.agiledata.bank.common.dao;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import cn.agiledata.bank.common.util.Constant;
import cn.agiledata.bank.common.util.PageBean;
import com.vnv.infrastructure.exception.IPBException;
import com.vnv.infrastructure.logic.IPBAppFactory;

public abstract class PageListTemplate extends HibernateDaoSupport implements
		PageList {

	public abstract Object getEntityObj();

	public abstract Map getPara();

	public abstract int getStartPage();

	public abstract String getSqlStr();

	public abstract int getPageSize();

	public PageListTemplate() {

		this.setSessionFactory((SessionFactory) IPBAppFactory
				.getObj("sessionFactory"));

	}

	/**
	 * 字符串封装方法
	 * 
	 * @return
	 */
	private String pickupStr() {
		Object obj = getEntityObj();

		// 得到最初的sql脚本
		String sqlStr = getSqlStr();
		// 经过整理得到客户定义好的field，保存到firldNames数组中
		String firstStr = sqlStr.substring(sqlStr.indexOf("select") + 6, sqlStr
				.indexOf("from"));
		String[] fields = StringUtils.split(firstStr, "}");
		String[] fieldNames = fields;
		for (int i = 0; i < fieldNames.length - 1; i++) {
			fieldNames[i] = fields[i].substring(fields[i]
					.indexOf(getClassName(obj.getClass().getName()))
					+ getClassName(obj.getClass().getName()).length() + 1,
					fields[i].length());
		}

		StringBuffer sb = new StringBuffer();
		// 得到封装对象的所有定义字段
		Field[] objs = obj.getClass().getDeclaredFields();
		// 判断如果用户没有定义，自动封装字段
		for (int i = 0; i < objs.length; i++) {
			Field field = objs[i];
			if (StringUtils.indexOfAny(field.getName(), fieldNames) != 0) {
				sb.append(", null as {").append(
						getClassName(obj.getClass().getName())).append(".")
						.append(field.getName()).append("}");
			}
		}
		// 将封装的字段加到最初的脚本，返回
		String returnStr = sqlStr.substring(0, sqlStr.indexOf("from"))
				+ sb.toString().substring(0, sb.toString().length())
				+ sqlStr.substring(sqlStr.indexOf("from") - 1);
		return returnStr;
	}

	private String getClassName(String allName) {
		return allName.substring(allName.lastIndexOf(".") + 1);
	}

	public PageBean getAccountListPageBean() {
		PageBean pb = new PageBean(getPageCount(), getStartPage(),
				getPageSize());
		pb.setData(getPageList());
		return pb;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see cn.agiledata.bank.common.dao.PageList#getPageList()
	 */
	private List getPageList() {

		Callback call = new Callback(pickupStr(), false);
		return (List) getHibernateTemplate().execute(call);

	}

	private int getPageCount() {

		String countStr = "select count(*) as count "
				+ pickupStr().substring(pickupStr().indexOf("from"),pickupStr().indexOf("order by"));
		Integer integer = (Integer) getHibernateTemplate().execute(
				new Callback(countStr, true));
		return integer.intValue();
	}

	class Callback implements HibernateCallback {
		private String hiSql;

		private boolean ifCount;

		public Callback(String hiSql, boolean ifCount) {
			this.hiSql = hiSql;
			this.ifCount = ifCount;
		}

		public Object doInHibernate(Session session) throws HibernateException {
			Query query = aa(session, hiSql);
			if (!ifCount) {

				List a = query.list();
				
				Query query1 = bb(session, hiSql);
				List b = query1.list();
				if(b!=null && b.size()>=1){
					a.add(0,b.get(0));
				}
				return a;
			}
			return query.uniqueResult();
		}

		private Query aa(Session session, String hiSql) {
			// 拼写query对象，addEntity指定封装到哪个对象中
			Query query;
			if (!ifCount) {
				query = session.createSQLQuery(hiSql.toString()).addEntity(
						getClassName(getEntityObj().getClass().getName()),
						getEntityObj().getClass());
				// 指定分页数据信息
				if (getStartPage() != -1) {
					int _temp_startPage = getStartPage();
					if (_temp_startPage <= 1) {
						_temp_startPage = 1;
					}
					query.setFirstResult((_temp_startPage - 1)
							* Constant.PAGESIZE.intValue() + 1);

					query.setMaxResults(Constant.PAGESIZE.intValue()-1);
					// query.setFetchSize(Constant.PAGESIZE.intValue());
				}
			} else {
				query = session.createSQLQuery(hiSql.toString()).addScalar(
						"count", Hibernate.INTEGER);
			}

			// 得到参数信息
			Map para = getPara();
			Iterator keyIter = para.keySet().iterator();
			// 封装参数信息
			// 如果是list对象，调用setParameterList
			// 如果是普通对象，调用setParameter
			while (keyIter.hasNext()) {
				String key = (String) keyIter.next();
				Object obj = para.get(key);
				if (obj instanceof List) {
					query.setParameterList(key, (Collection) obj);
				} else {
					query.setParameter(key, obj);
				}
			}
			return query;
		}

		private Query bb(Session session, String hiSql) {
			// 拼写query对象，addEntity指定封装到哪个对象中
			Query query = session.createSQLQuery(hiSql.toString()).addEntity(
					getClassName(getEntityObj().getClass().getName()),
					getEntityObj().getClass());
			// 指定分页数据信息
			if (getStartPage() != -1) {
				int _temp_startPage = getStartPage();
				if (_temp_startPage <= 1) {
					_temp_startPage = 1;
				}
				query.setFirstResult((_temp_startPage - 1)
						* Constant.PAGESIZE.intValue());
				query.setMaxResults(1);
				// query.setFetchSize(Constant.PAGESIZE.intValue());
			}

			// 得到参数信息
			Map para = getPara();
			Iterator keyIter = para.keySet().iterator();
			// 封装参数信息
			// 如果是list对象，调用setParameterList
			// 如果是普通对象，调用setParameter
			while (keyIter.hasNext()) {
				String key = (String) keyIter.next();
				Object obj = para.get(key);
				if (obj instanceof List) {
					query.setParameterList(key, (Collection) obj);
				} else {
					query.setParameter(key, obj);
				}
			}
			return query;
		}
	}
}
